package com.example.estest.watch;
import com.example.estest.config.MyThread;
import com.example.estest.config.RetryPolicy;
import com.example.estest.util.DateUtil;
import com.example.estest.util.FileUtils;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.file.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;


@Component("myFileWatcher")
public class FileWatcher {

    private static volatile boolean processingEvent = false;

    volatile Long start;

    volatile String startPosition;

    volatile int numlast;

    AtomicInteger atomicInteger = new AtomicInteger(1);


    public  void func(String logpath,RestHighLevelClient client,String path) {
        // 要监听的文件或目录路径

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(8, 16, 10,
                TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000), Executors.defaultThreadFactory(), new RetryPolicy());
        threadPoolExecutor.allowCoreThreadTimeOut(true);

        logPathUnil(logpath);


        String number = logpath+"\\"+"number";

        //遍历监听文件，记录每个文件初始日志，然后从该位置开始监听变化
        List<String> filetotal = new ArrayList<>();
        File file4 = new File(path);
        FileUtils.visitAllDirsAndFiles(file4,filetotal);
        filetotal.remove(file4.getAbsolutePath());
        for (String filepath:filetotal) {
            try {
                int length = Files.readAllBytes(Paths.get(filepath)).length;
                //截取拿到日志文件名字
                String strings = filepath.substring(file4.getAbsolutePath().length()+1);
                strings = strings.split("\\.")[0];
                File file3 = new File(number+"\\"+"account_"+strings+".txt");
                if(!file3.exists()) {
                    file3.createNewFile();
                    FileUtils.writeString(file3.getAbsolutePath(),String.valueOf(length));
                }else {
                    FileUtils.writeString(file3.getAbsolutePath(),String.valueOf(length));
                }
            } catch (IOException e) {
                FileUtils.writeStringadd(logpath+"\\"+"error.log", DateUtil.getData()+"------"+"遍历监听文件读取原始长度出异常");
                throw new RuntimeException(e);
            }
        }



        try {
            // 创建 WatchService
            WatchService watchService = FileSystems.getDefault().newWatchService();
            // 注册监听的事件类型（这里注册了 ENTRY_MODIFY，即文件内容修改事件）
            Path dir = Paths.get(path);   //监听目录
            dir.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);

            new Thread(() -> {
                try {
                    while (true) {
                        synchronized (FileWatcher.class) {

                            WatchKey key = watchService.take(); // 阻塞等待事件
                            for (WatchEvent<?> event : key.pollEvents()) {
                                if (!processingEvent && event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) {
                                    processingEvent = true; // 设置标志位，表示正在处理事件

                                    WatchEvent<Path> pathEvent = (WatchEvent<Path>) event;
                                    Path fileName = pathEvent.context();
                                    //监听目录下以.json结尾的日志文件
                                    if(fileName.toString().endsWith(".json")) {
                                        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM");
                                        LocalDateTime currentDateTime = LocalDateTime.now();
                                        String month = currentDateTime.format(dateTimeFormatter);

                                        monthFile(logpath,month);

                                        numlast = Files.readAllBytes(Paths.get(path+"\\"+fileName)).length;

                                        String filenames = fileName.toString().split("\\.")[0];  //截取文件名字

                                        String receivelog = logpath+"\\"+"receive"+"\\"+month+"\\"+"receive_"+filenames+".txt";
                                        String finishlog = logpath+"\\"+"finish"+"\\"+month+"\\"+"finishlog_"+filenames+".txt";

                                        fileUtil(receivelog,finishlog,logpath);

                                        //这是每天第一条日志来的时候，检验记录光标的文本是否存在，不存在就创建
                                        File file3 = new File(number+"\\"+"account_"+filenames+".txt");
                                        if(!file3.exists()) {
                                            file3.createNewFile();
                                        }

                                        startPosition = FileUtils.readString(file3.getAbsolutePath());
                                        //处理测试过程bug
                                        if(startPosition.isEmpty()) {
                                            startPosition = "0";
                                        }
                                        RandomAccessFile raf = new RandomAccessFile(path+"\\"+fileName, "r");

                                        start = Long.parseLong(startPosition);
                                        // 将文件指针移动到指定位置
                                        //开发中测试bug
                                        if(start > numlast) {
                                            start = (long) 0;
                                        }
                                        raf.seek(start);
                                        String line;
                                        //用来记算这次读取应该到哪结束
                                        Long count =  start;

                                        while ((line = raf.readLine()) != null) {
                                            if(line.isEmpty()) {
                                                continue;
                                            }
                                            if(count == numlast) {
                                                break;
                                            }
                                            int old = line.length();
                                            line = line.trim();
                                            int newlength = line.length();
                                            FileUtils.writeStringadd(receivelog, DateUtil.getData()+"------"+"收到一条日志"+line);
                                            threadPoolExecutor.execute(new MyThread(line,path+"\\"+fileName,logpath,client,finishlog,atomicInteger.getAndIncrement()));
                                            //加二是英文每个日志后面有\r\n(根据日志写入方式)
                                            count += line.length()+2;
                                        }
                                        FileUtils.writeString(file3.getAbsolutePath(),String.valueOf(numlast));

                                    }

                                    processingEvent = false; // 处理完毕，重置标志位
                                    //防止线程池线程取名字一直增加超过int值
                                    atomicInteger.set(0);
                                }
                            }
                            key.reset();
                        }
                    }
                } catch (IOException | InterruptedException e) {
                    FileUtils.writeStringadd(logpath+"\\"+"error.log", DateUtil.getData()+"------"+e.getMessage());
                    e.printStackTrace();
                }
            }).start();

        } catch (IOException e) {
            FileUtils.writeStringadd(logpath+"\\"+"error.log", DateUtil.getData()+"------"+e.getMessage());
            e.printStackTrace();
        }
    }


    /**
     * 启动时创建程序记录日志的文件
     * @param logpath
     */
    private static void logPathUnil(String logpath) {

        //检验错误日志文件是否存在
        File errorFile = new File(logpath+"\\"+"error.log");
        if(!errorFile.exists()) {
            try {
                errorFile.createNewFile();
            } catch (IOException e) {
                System.out.println("创建错误日志异常");
                throw new RuntimeException(e);
            }
        }
        String errorPath = errorFile.getAbsolutePath();

        File file = new File(logpath+"\\"+"finish");
        if(!file.exists()) {
            FileUtils.createDirectory(file.getPath(),errorPath);
        }
        File file1 = new File(logpath+"\\"+"receive");
        if(!file1.exists()) {
            FileUtils.createDirectory(file1.getPath(),errorPath);
        }
        File file2 = new File(logpath+"\\"+"number");
        if(!file2.exists()) {
            FileUtils.createDirectory(file2.getAbsolutePath(),errorPath);
        }
    }



    /**
     * 检验记录每天日志的文本是否存在，不存在就创建
     * @param receivelog
     * @param finishlog
     * @param logpath
     */
    public static void fileUtil(String receivelog,String finishlog,String logpath) {
        //检验接收日志文件是否存在
        File file = new File(receivelog);
        if(!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                FileUtils.writeStringadd(logpath+"\\"+"error.log", DateUtil.getData()+"------"+receivelog+"文件创建失败");
                throw new RuntimeException(e);
            }
        }

        //检验完成日志是否存在
        File file1 = new File(finishlog);
        if(!file1.exists()) {
            try {
                file1.createNewFile();
            } catch (IOException e) {
                FileUtils.writeStringadd(logpath+"\\"+"error.log", DateUtil.getData()+"------"+finishlog+"文件创建失败");
                throw new RuntimeException(e);
            }
        }
    }

    public static void monthFile(String logpath,String month) {
        String monthFileReceive = logpath+"\\"+"receive"+"\\"+month;
        File file = new File(monthFileReceive);
        if(!file.exists()) {
            FileUtils.createDirectory(file.getAbsolutePath(),logpath+"\\"+"error.log");
        }
        String monthFileFinish = logpath+"\\"+"finish"+"\\"+month;
        File file1 = new File(monthFileFinish);
        if(!file1.exists()) {
            FileUtils.createDirectory(file1.getAbsolutePath(),logpath+"\\"+"error.log");
        }
    }

}



